//实现获取 下一个排列 的函数，算法需要将给定数字序列重新排列成字典序中下一个更大的排列（即，组合出下一个更大的整数）。 
//
// 如果不存在下一个更大的排列，则将数字重新排列成最小的排列（即升序排列）。 
//
// 必须 原地 修改，只允许使用额外常数空间。 
//
// 
//
// 示例 1： 
//
// 
//输入：nums = [1,2,3]
//输出：[1,3,2]
// 
//
// 示例 2： 
//
// 
//输入：nums = [3,2,1]
//输出：[1,2,3]
// 
//
// 示例 3： 
//
// 
//输入：nums = [1,1,5]
//输出：[1,5,1]
// 
//
// 示例 4： 
//
// 
//输入：nums = [1]
//输出：[1]
// 
//
// 
//
// 提示： 
//
// 
// 1 <= nums.length <= 100 
// 0 <= nums[i] <= 100 
// 
// Related Topics 数组 双指针 👍 1381 👎 0

package leetcode.editor.cn;

import java.util.Arrays;

public class _31_NextPermutation {
    public static void main(String[] args) {
        int[] nums = new int[]{1, 5, 8, 4, 7, 6, 5, 3, 1};
        Solution solution = new _31_NextPermutation().new Solution();
        solution.nextPermutation(nums);
        System.out.println(Arrays.toString(nums));
    }

    class Solution {
        public void nextPermutation(int[] nums) {
            int index = nums.length;
            for (int i = nums.length - 2; i >= 0; i--) {
                if (nums[i] < nums[i + 1]) {
                    index = i;
                    break;
                }
            }
            if (index == nums.length) {
                reverse(nums, 0);
            } else {
                for (int i = nums.length - 1; i >= index; i--) {
                    if (nums[i] > nums[index]) {
                        swap(nums, i, index);
                        break;
                    }
                }
                reverse(nums, index + 1);
            }
        }

        private void reverse(int[] nums, int i) {
            int left = i;
            int right = nums.length - 1;
            while (left < right) {
                swap(nums, left, right);
                left++;
                right--;
            }
        }

        private void swap(int[] nums, int i, int j) {
            int temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
        }
    }

    //leetcode submit region begin(Prohibit modification and deletion)
    class Solution1 {
        public void nextPermutation(int[] nums) {
            int i = nums.length - 2;
            while (i >= 0 && nums[i] >= nums[i + 1]) {
                i--;
            }
            if (i >= 0) {
                int j = nums.length - 1;
                while (j >= 0) {
                    if (nums[j] > nums[i]) {
                        break;
                    }
                    j--;
                }
                swap(nums, i, j);
            }
            reverse(nums, i + 1);
        }

        private void reverse(int[] nums, int j) {
            int left = j;
            int right = nums.length - 1;
            while (left < right) {
                swap(nums, left++, right--);
            }
        }

        public void nextPermutation_2(int[] nums) {
            int index = -1;
            for (int i = nums.length - 2; i >= 0; i--) {
                index = findBiggerBehind(nums, i);
                if (index != i) {
                    swap(nums, i, index);
                    Arrays.sort(nums, i + 1, nums.length);
                    break;
                }
            }
            if (index == 0) {
                Arrays.sort(nums);
            }
        }

        private void swap(int[] nums, int a, int b) {
            int tmp = nums[a];
            nums[a] = nums[b];
            nums[b] = tmp;
        }

        private int findBiggerBehind(int[] nums, int index) {
            int bigger = index;
            for (int i = index + 1; i < nums.length; i++) {
                if (nums[i] > nums[index] && (bigger == index ? true : nums[i] <= nums[bigger])) {
                    bigger = i;
                }
            }
            return bigger;
        }
    }
//leetcode submit region end(Prohibit modification and deletion)

}